package com.starleague.jpa.appengine;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FlushModeType;
import javax.persistence.Persistence;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.appengine.api.datastore.Key;
import com.starleague.jpa.JpaPersistManager;

public class GaePersistManager
        implements JpaPersistManager<Key, GaeDao>
{
    private static final Logger log = LoggerFactory.getLogger(GaePersistManager.class);

    private final EntityManagerFactory entityManagerFactory;
    // @PersistenceContext(type=PersistenceContextType.EXTENDED)
    private final EntityManager entityManager;

    // private int emVersion = 1;

    public GaePersistManager(String persistenceUnitName)
    {
        this.entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
        this.entityManager = this.entityManagerFactory.createEntityManager();
        this.entityManager.setFlushMode(FlushModeType.COMMIT);
    }

    // EntityManagerFactory getEntityManagerFactory()
    // {
    // return this.entityManagerFactory;
    // }

    //
    // Transaction management
    //

    @Override
    public GaeTransaction startTransaction()
    {
        return new GaeTransaction(this.entityManager);
    }

    @Override
    public void close()
    {
        if (this.entityManager.isOpen())
        {
            try
            {
                this.entityManager.close();
            }
            catch (final Exception e)
            {
                log.error("close() failed: ", e);
            }
        }
    }

    // public Query createNamedQuery(final String queryName)
    // {
    // return this.entityManager.createNamedQuery(queryName);
    // }
    //
    // public Query createQuery(final String queryStr)
    // {
    // return this.entityManager.createQuery(queryStr);
    // }
    //
    // public <DAO extends GaeDao> DAO find(final Class<DAO> daoClass, final Key
    // daoIdKey)
    // {
    // return this.entityManager.find(daoClass, daoIdKey);
    // }
    //
    // public void persist(final GaeDao dao)
    // {
    // if (!this.entityManager.contains(dao))
    // {
    // this.entityManager.persist(dao);
    // this.entityManager.flush();
    // }
    // }
    //
    // // public void refresh(final Dao i_dao)
    // // {
    // // this.entityManager.refresh(i_dao);
    // // this.entityManager.flush();
    // // }
    //
    // public <DAO extends GaeDao> DAO merge(final DAO dao)
    // {
    // if (!this.entityManager.contains(dao))
    // {
    // final DAO newDao = this.entityManager.merge(dao);
    // this.entityManager.flush();
    // return newDao;
    // }
    // // else
    // return dao;
    // }
    //
    // //
    // // Proxy Management
    // //
    //
    // public <DAO extends GaeDao> void addProxy(final GaeProxy<DAO> proxy)
    // throws StarLeagueException
    // {
    // final Key idKey = proxy.getDao().getIdKey();
    //
    // if (idKey == null)
    // throw new StarLeagueException("Null Key for: " + proxy);
    //
    // if (this.keyProxyMap.containsKey(idKey))
    // throw new StarLeagueException("Mapping already exists for key [" + idKey
    // + "]");
    //
    // this.keyProxyMap.put(idKey, proxy);
    // }
    //
    // public <DAO extends GaeDao> boolean removeProxy(final GaeProxy<DAO>
    // proxy)
    // {
    // // TODO: Order of operations (remove from map before removing from DB?)
    // final boolean proxyRemoved =
    // (this.keyProxyMap.remove(proxy.getDao().getIdKey()) != null);
    //
    // final DAO newDao = this.entityManager.merge(proxy.getDao());
    // this.entityManager.remove(newDao);
    // this.entityManager.flush();
    //
    // return proxyRemoved;
    // }
    //
    // @SuppressWarnings("unchecked")
    // public <PROXY> PROXY lookupCachedProxy(final Key daoIdKey, final
    // Class<PROXY> proxyClass)
    // throws StarLeagueException
    // {
    // if ((daoIdKey == null) || !this.keyProxyMap.containsKey(daoIdKey))
    // return null;
    //
    // try
    // {
    // final GaeProxy<? extends GaeDao> proxy = this.keyProxyMap.get(daoIdKey);
    // if (proxy == null)
    // return null;
    // // else
    // if (!proxyClass.isAssignableFrom(proxy.getClass()))
    // throw new StarLeagueException("PersistManager.lookupCachedProxy(): key ["
    // + daoIdKey + "] is not a ["
    // + proxyClass.getName() + "]");
    // return (PROXY) proxy;
    // } catch (final StarLeagueException e)
    // {
    // throw e;
    // } catch (final Throwable e)
    // {
    // throw new StarLeagueException(e);
    // }
    // }
    //
    // public <PROXY extends GaeProxy<?>> PROXY refreshProxy(final PROXY proxy)
    // {
    // proxy.merge();
    // this.entityManager.refresh(proxy.getDao());
    // // this.entityManager.flush();
    // return proxy;
    // }

}
// public static MechEngineDao.Proxy lookup(
// final EntityManager i_entityManager,
// final Key i_daoIdKey) throws StarLeagueException
// {
// synchronized(proxyManager)
// {
// final MechEngineDao.Proxy proxy =
// (MechEngineDao.Proxy)proxyManager.lookupProxy(i_daoIdKey);
// if (proxy != null)
// return proxy;
// // else
// return new MechEngineDao.Proxy(i_entityManager,
// i_entityManager.find(MechEngineDao.class, i_daoIdKey));
// }
// }
//
// public PersistManager()
// {
// this.entityManager =
// Persistence.createEntityManagerFactory(DEFAULT_PERSISTENCE_UNIT).createEntityManager();
// }
//
// // public <T> T persist(final T i_obj)
// public <T> void persist(final T i_obj)
// {
// this.entityManager.persist(i_obj);
// }
//
// public Query createNamedQuery(final String i_queryName)
// {
// return this.entityManager.createNamedQuery(i_queryName);
// }
//
// // public <T> T merge(final T i_obj)
// // {
// // return this.entityManager.merge(i_obj);
// // }
// //
// // public <T> Dao<T> find(final Dao<T> i_dao)
// // {
// // return this.entityManager.merge(i_dao);
// // }
//
// public <T> T persist(final T ... i_objs) throws Throwable
// {
// EntityTransaction transaction = this.entityManager.getTransaction();
//
// try
// {
// log.info("persist(): Starting Transaction");
// transaction.begin();
//
// for (final T obj : i_objs)
// {
// try
// {
// final T newObj = this.entityManager.merge(obj);
// this.entityManager.persist(newObj);
// this.entityManager.flush();
// }
// catch(javax.persistence.EntityExistsException e)
// {
// log.warn("Got Error: " + e.getMessage());
// e.printStackTrace();
// }
// catch(Throwable e)
// {
// log.warn("Got Error: " + e.getMessage());
// e.printStackTrace();
// throw new PersistException(e);
// }
// }
//
// // this.entityManager.flush();
//
// log.info("persist(): Commiting Transaction");
// transaction.commit();
// transaction = null;
//
// return true;
// }
// catch(final RollbackException e)
// {
// throw e.getCause();
// }
// finally
// {
// if (transaction != null)
// try { transaction.rollback(); } catch(final Throwable e) {}
// }
// }
//
// public <T> boolean remove(final T ... i_objs) throws Throwable
// {
// EntityTransaction transaction = this.entityManager.getTransaction();
//
// try
// {
// log.info("remove(): Starting Transaction");
// transaction.begin();
//
// for (final T obj : i_objs)
// {
// try
// {
// this.entityManager.remove(obj);
// this.entityManager.flush();
// }
// catch(javax.persistence.EntityExistsException e)
// {
// log.warn("Got Error: " + e.getMessage());
// e.printStackTrace();
// }
// catch(Throwable e)
// {
// log.warn("Got Error: " + e.getMessage());
// e.printStackTrace();
// throw new PersistException(e);
// }
// }
//
// // this.entityManager.flush();
//
// log.info("remove(): Commiting Transaction");
// transaction.commit();
// transaction = null;
//
// return true;
// }
// catch(final RollbackException e)
// {
// throw e.getCause();
// }
// finally
// {
// if (transaction != null)
// try { transaction.rollback(); } catch(final Throwable e) {}
// }
// }
//
// // public boolean refresh(final Object ... i_objects) throws Throwable
// // {
// // EntityTransaction transaction = this.entityManager.getTransaction();
// //
// // try
// // {
// // log.info("Starting Transaction");
// // transaction.begin();
// //
// // for (Object obj : i_objects)
// // DataAccessObject.refresh(this.entityManager, obj);
// //
// //// this.entityManager.flush();
// //
// // log.info("Commiting Transaction");
// // transaction.commit();
// // transaction = null;
// //
// // return true;
// // }
// // catch(final RollbackException e)
// // {
// // throw e.getCause();
// // }
// // finally
// // {
// // if (transaction != null)
// // try { transaction.rollback(); } catch(final Throwable e) {}
// // }
// // }
//
// private final EntityManager entityManager;
//
// private static final Logger log = Logger.getLogger(PersistManager.class);

//
//
//
// //Annotation[] classAnnotations = obj.getClass().getAnnotations();
// //for(Annotation classAnnotation : classAnnotations)
// //{
// // if (classAnnotation instanceof DataAccessObject.DaoClass)
// // {
// // Class<? extends DataAccessObject> daoClass =
// // ((DataAccessObject.DaoClass)classAnnotation).value();
// //
// // DataAccessObject.Manager dao_manager = classDaoFactoryMap.get(daoClass);
// //
// // if (factory == null)
// // {
// // factory = this.createFactory(daoClass);
// // classDaoFactoryMap.put(daoClass, factory);
// // log.error("Created factory [" + factory + "] for DAO class [" + daoClass +
// "]");
// // }
// //
// // dao = factory.create(obj);
// // objectDaoMap.put(obj, dao);
// // log.error("Created dao [" + dao + "]");
// //
// // break;
// // }
// //}
// //DataAccessObject dao = objectDaoMap.get(obj);
// //
// //if (dao == null)
// ////{
// // Annotation[] classAnnotations = obj.getClass().getAnnotations();
// // for(Annotation classAnnotation : classAnnotations)
// // {
// // if (classAnnotation instanceof DataAccessObject.DaoClass)
// // {
// Class<? extends DataAccessObject> daoClass =
// ((DataAccessObject.DaoClass)classAnnotation).value();
//
// DataAccessObject.Factory factory = classDaoFactoryMap.get(daoClass);
//
// if (factory == null)
// {
// factory = this.createFactory(daoClass);
// classDaoFactoryMap.put(daoClass, factory);
// log.error("Created factory [" + factory + "] for DAO class [" + daoClass +
// "]");
// }
//
// dao = factory.create(obj);
// objectDaoMap.put(obj, dao);
// log.error("Created dao [" + dao + "]");
//
// break;
// }
// }
